/* this source file include definitions defined in 4 source files
 * phys_mm.c, virt_mm.c, and page_mm.c. I know its considered bad
 * practice to have one header for 3 sources, but I only did it
 * to organize the overall memory manager in parts and make it
 * easier to read and understand. mm.c is the main source file 
 */

#ifndef __MM_H
#define __MM_H

#include "typedef.h"

#define		PG_SIZE       	 4096
#define         PG_PRES          0x00000001
#define         PG_READ          0x0
#define         PG_WRITE         0x00000002
#define         PG_USER          0x00000004
#define         PG_SUPER         0x0
#define         PG_COW           0x800     // this is the bit we choose to signify copy on write
#define         PG_LINKED        0x400     // this bit signifies table was linked into directory
#define         PG_SHARED        0x200     // signified a shared table
#define         PG_REF     (PG_COW | PG_LINKED | PG_SHARED) // overall flag to see if a page is some kind of reference


// paging macros for accessing page flags
#define		PG_ALIGN(X)	 (X & 0xfffff000)
#define         PG_FRAME(X)      (X & 0xfffff000)
#define         PDE_OFFSET(X)    (X >> 22)
#define         PTE_OFFSET(X)    ((X & 0x003ff000) >> 12)
#define		PG_VALID(X)	 (X & 0x00000001)
#define		PG_DIRTY(X)	 (X & 0x00000040)
#define		PG_ACCESSED(X)	 (X & 0x00000020)
#define         PG_PERM(X)       (X & 0x7)


#define         MM_ERROR_MAGIC       0xDEADC0DE

// descriptor for allocated pages. this is for pages pointed to by other
// pages and keeps track of how many references they get
typedef struct big_page_desc_struct {
  u32 addr;
  u32 ref_count;   // this means no one is referencing this table
  u32 free;        // this means the directory storing this table is active
  u32 in_use;
  struct big_page_desc_struct* next;
  struct big_page_desc_struct* prev;
} big_page_desc;

// this one is for pages that reference other pages, and designate the link type
typedef struct little_page_desc_struct {
  u32 addr;
  big_page_desc* ref_page;
  struct little_page_desc_struct* next;
  struct little_page_desc_struct* prev;
} little_page_desc;

// a page is essentially just 4 bytes. Use macros to get info about it
typedef u32 page_t;

typedef struct pte {
  u32 pages[1024];
} pte_t;

typedef struct pde {
  pte_t* tables[1024];
} pde_t;

// page directorys
pde_t* kernel_dir;
pde_t* cur_dir;

/****************************************************************
// functions defined in mm.s
***************************************************************/
void load_CR3(u32);
u32 get_CR2();
void enable_paging();

/****************************************************************
// functions for mm.c
***************************************************************/
void init_mm();
u32 virt_to_phys(pde_t*, u32);
void switch_page_directory(pde_t*);
pde_t* clone_pde(pde_t*);
void free_pde(pde_t*);
pte_t* clone_pte(pte_t*, u32);
void free_pte(pte_t*);
void map_area(pde_t*, u32, u32, u32);
void copy_frame(u32 source, u32 dest);
void debug_mm();
void debug_little_desc_list();
void debug_big_desc_list();
void debug_list();

/****************************************************************
// functions for virt_mm.c
***************************************************************/

void init_virt_mm();
u32 get_page();
void free_page(u32);
void debug_virt_mm();

/****************************************************************
// functions for phys_mm.c
***************************************************************/
void init_phys_mm();
u32 get_frame();
void free_frame(u32);
void debug_phys_mm();



#endif
